﻿using System.Runtime.InteropServices;
using System;
using System.ComponentModel;

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
class MEMORYSTATUSEX
{
    public uint dwLength;
    public uint dwMemoryLoad;
    public ulong ullTotalPhys;
    public ulong ullAvailPhys;
    public ulong ullTotalPageFile;
    public ulong ullAvailPageFile;
    public ulong ullTotalVirtual;
    public ulong ullAvailVirtual;
    public ulong ullAvailExtendedVirtual;

    public MEMORYSTATUSEX()
    {
        this.dwLength = (uint)Marshal.SizeOf(this.GetType());
    }
}


public class GlobalMemoryStatus
{
    [return: MarshalAs(UnmanagedType.Bool)]
    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern bool GlobalMemoryStatusEx([In, Out] MEMORYSTATUSEX lpBuffer);

    /// <summary>
    /// Number between 0 and 100 that specifies the approximate percentage of physical memory that is in use (0 indicates no memory use and 100 indicates full memory use).
    /// </summary>
    public int MemoryLoad { get; private set; }

    /// <summary>
    /// Total size of physical memory, in bytes.
    /// </summary>
    public ulong TotalPhysical { get; private set; }
    
    /// <summary>
    /// Size of physical memory available, in bytes.
    /// </summary>
    public ulong AvailablePhysical { get; private set; }

    /// <summary>
    /// Size of the committed memory limit, in bytes. This is physical memory plus the size of the page file, minus a small overhead.
    /// </summary>
    public ulong TotalPageFile { get; private set; }

    /// <summary>
    /// Size of available memory to commit, in bytes. The limit is ullTotalPageFile.
    /// </summary>
    public ulong AvailablePageFile { get; private set; }

    private GlobalMemoryStatus ()
	{}

    public static GlobalMemoryStatus Get()
    {
        MEMORYSTATUSEX status = new MEMORYSTATUSEX();
        if (!GlobalMemoryStatusEx(status))
            throw new ApplicationException("GlobalMemoryStatusEx failed", new Win32Exception(Marshal.GetLastWin32Error()));

        return new GlobalMemoryStatus()
        {
            MemoryLoad = (int)status.dwMemoryLoad,

            TotalPhysical = status.ullTotalPhys,
            AvailablePhysical = status.ullAvailPhys,

            TotalPageFile = status.ullTotalPageFile,
            AvailablePageFile = status.ullAvailPageFile
        };
    }
}
